1   /*                        __    __  __  __    __  ___
2    *                       \  \  /  /    \  \  /  /  __/
3    *                        \  \/  /  /\  \  \/  /  /
4    *                         \____/__/  \__\____/__/.ɪᴏ
5    * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
6    */
7   package io.vavr.collection;
8   
9   import io.vavr.Tuple;
10  import io.vavr.Tuple2;
11  import io.vavr.Tuple3;
12  import io.vavr.control.Option;
13  import org.assertj.core.api.Assertions;
14  import org.assertj.core.api.IterableAssert;
15  import org.assertj.core.api.ObjectAssert;
16  import org.junit.Ignore;
17  import org.junit.Test;
18  
19  import java.math.BigDecimal;
20  import java.util.ArrayList;
21  import java.util.Comparator;
22  import java.util.NoSuchElementException;
23  import java.util.Spliterator;
24  import java.util.concurrent.ExecutorService;
25  import java.util.concurrent.Executors;
26  import java.util.function.Function;
27  import java.util.function.Supplier;
28  import java.util.stream.Collector;
29  
30  import static io.vavr.collection.Iterator.*;
31  
32  public class IteratorTest extends AbstractTraversableTest {
33  
34      @Override
35      protected <T> IterableAssert<T> assertThat(Iterable<T> actual) {
36          return new IterableAssert<T>(actual) {
37              @SuppressWarnings("unchecked")
38              @Override
39              public IterableAssert<T> isEqualTo(Object expected) {
40                  if (actual instanceof Option) {
41                      final Option<?> opt1 = ((Option<?>) actual);
42                      final Option<?> opt2 = (Option<?>) expected;
43                      Assertions.assertThat(wrapIterator(opt1)).isEqualTo(wrapIterator(opt2));
44                      return this;
45                  } else {
46                      final Iterable<T> iterable = (Iterable<T>) expected;
47                      Assertions.assertThat(List.ofAll(actual)).isEqualTo(List.ofAll(iterable));
48                      return this;
49                  }
50              }
51  
52              private Option<?> wrapIterator(Option<?> option) {
53                  return option.map(o -> (o instanceof Iterator) ? List.ofAll((Iterator<?>) o) : o);
54              }
55          };
56      }
57  
58      @Override
59      protected <T> ObjectAssert<T> assertThat(T actual) {
60          return new ObjectAssert<T>(actual) {
61              @Override
62              public ObjectAssert<T> isEqualTo(Object expected) {
63                  if (actual instanceof Tuple2) {
64                      final Tuple2<?, ?> t1 = ((Tuple2<?, ?>) actual).map(this::toList);
65                      final Tuple2<?, ?> t2 = ((Tuple2<?, ?>) expected).map(this::toList);
66                      Assertions.assertThat((Object) t1).isEqualTo(t2);
67                      return this;
68                  } else if (actual instanceof Tuple3) {
69                      final Tuple3<?, ?, ?> t1 = ((Tuple3<?, ?, ?>) actual).map(this::toList);
70                      final Tuple3<?, ?, ?> t2 = ((Tuple3<?, ?, ?>) expected).map(this::toList);
71                      Assertions.assertThat((Object) t1).isEqualTo(t2);
72                      return this;
73                  } else {
74                      return super.isEqualTo(expected);
75                  }
76              }
77  
78              private Tuple2<Object, Object> toList(Object o1, Object o2) {
79                  return Tuple.of(wrapIterator(o1), wrapIterator(o2));
80              }
81  
82              private Tuple3<Object, Object, Object> toList(Object o1, Object o2, Object o3) {
83                  return Tuple.of(wrapIterator(o1), wrapIterator(o2), wrapIterator(o3));
84              }
85  
86              private Object wrapIterator(Object o) {
87                  return (o instanceof Iterator) ? List.ofAll((Iterator<?>) o) : o;
88              }
89          };
90      }
91  
92      @Override
93      protected <T> Collector<T, ArrayList<T>, ? extends Iterator<T>> collector() {
94          throw new UnsupportedOperationException();
95      }
96  
97      @Override
98      protected <T> Iterator<T> empty() {
99          return Iterator.empty();
100     }
101 
102     @Override
103     protected <T> Iterator<T> of(T element) {
104         return Iterator.of(element);
105     }
106 
107     @SuppressWarnings("varargs")
108     @SafeVarargs
109     @Override
110     protected final <T> Iterator<T> of(T... elements) {
111         return Iterator.of(elements);
112     }
113 
114     @Override
115     protected <T> Iterator<T> ofAll(Iterable<? extends T> elements) {
116         return Iterator.ofAll(elements);
117     }
118 
119     @Override
120     protected <T extends Comparable<? super T>> Iterator<T> ofJavaStream(java.util.stream.Stream<? extends T> javaStream) {
121         return Iterator.ofAll(javaStream.iterator());
122     }
123 
124     @Override
125     protected Iterator<Boolean> ofAll(boolean... elements) {
126         return Iterator.ofAll(elements);
127     }
128 
129     @Override
130     protected Iterator<Byte> ofAll(byte... elements) {
131         return Iterator.ofAll(elements);
132     }
133 
134     @Override
135     protected Iterator<Character> ofAll(char... elements) {
136         return Iterator.ofAll(elements);
137     }
138 
139     @Override
140     protected Iterator<Double> ofAll(double... elements) {
141         return Iterator.ofAll(elements);
142     }
143 
144     @Override
145     protected Iterator<Float> ofAll(float... elements) {
146         return Iterator.ofAll(elements);
147     }
148 
149     @Override
150     protected Iterator<Integer> ofAll(int... elements) {
151         return Iterator.ofAll(elements);
152     }
153 
154     @Override
155     protected Iterator<Long> ofAll(long... elements) {
156         return Iterator.ofAll(elements);
157     }
158 
159     @Override
160     protected Iterator<Short> ofAll(short... elements) {
161         return Iterator.ofAll(elements);
162     }
163 
164     @Override
165     protected <T> Iterator<T> tabulate(int n, Function<? super Integer, ? extends T> f) {
166         return Iterator.tabulate(n, f);
167     }
168 
169     @Override
170     protected <T> Iterator<T> fill(int n, Supplier<? extends T> s) {
171         return Iterator.fill(n, s);
172     }
173 
174     @Override
175     protected boolean useIsEqualToInsteadOfIsSameAs() {
176         return true;
177     }
178 
179     @Override
180     protected int getPeekNonNilPerformingAnAction() {
181         return 3;
182     }
183 
184     @Test(expected = NoSuchElementException.class)
185     public void shouldFailOfEmptyArgList() {
186         of().next();
187     }
188 
189     // -- static narrow()
190 
191     @Test
192     public void shouldNarrowIterator() {
193         final Iterator<Double> doubles = of(1.0d);
194         final Iterator<Number> numbers = narrow(doubles);
195         final int actual = numbers.concat(Iterator.of(new BigDecimal("2.0"))).sum().intValue();
196         assertThat(actual).isEqualTo(3);
197     }
198 
199     // -- static ofAll()
200 
201     @Test(expected = NoSuchElementException.class)
202     public void shouldFailOfEmptyIterable() {
203         ofAll(List.empty()).next();
204     }
205 
206     @Test(expected = NoSuchElementException.class)
207     public void shouldFailOfEmptyBoolean() {
208         ofAll(new boolean[0]).next();
209     }
210 
211     @Test(expected = NoSuchElementException.class)
212     public void shouldFailOfEmptyByte() {
213         ofAll(new byte[0]).next();
214     }
215 
216     @Test(expected = NoSuchElementException.class)
217     public void shouldFailOfEmptyChar() {
218         ofAll(new char[0]).next();
219     }
220 
221     @Test(expected = NoSuchElementException.class)
222     public void shouldFailOfEmptyDouble() {
223         ofAll(new double[0]).next();
224     }
225 
226     @Test(expected = NoSuchElementException.class)
227     public void shouldFailOfEmptyFloat() {
228         ofAll(new float[0]).next();
229     }
230 
231     @Test(expected = NoSuchElementException.class)
232     public void shouldFailOfEmptyInt() {
233         ofAll(new int[0]).next();
234     }
235 
236     @Test(expected = NoSuchElementException.class)
237     public void shouldFailOfEmptyLong() {
238         ofAll(new long[0]).next();
239     }
240 
241     @Test(expected = NoSuchElementException.class)
242     public void shouldFailOfEmptyShort() {
243         ofAll(new short[0]).next();
244     }
245 
246     // -- static concat()
247 
248     @Test
249     public void shouldConcatEmptyIterableIterable() {
250         final Iterable<Iterable<Integer>> empty = List.empty();
251         assertThat(concat(empty)).isSameAs(Iterator.empty());
252     }
253 
254     @Test
255     public void shouldConcatNonEmptyIterableIterable() {
256         final Iterable<Iterable<Integer>> itIt = List.of(List.of(1, 2), List.of(3));
257         assertThat(concat(itIt)).isEqualTo(Iterator.of(1, 2, 3));
258     }
259 
260     @Test
261     public void shouldConcatEmptyArrayIterable() {
262         assertThat(concat()).isSameAs(Iterator.empty());
263     }
264 
265     @Test
266     public void shouldConcatNonEmptyArrayIterable() {
267         assertThat(concat(List.of(1, 2), List.of(3))).isEqualTo(Iterator.of(1, 2, 3));
268     }
269 
270     // -- concat
271 
272     @Test
273     public void shouldConcatThisNonEmptyWithEmpty() {
274         final Iterator<Integer> it = Iterator.of(1);
275         assertThat(it.concat(Iterator.<Integer> empty())).isSameAs(it);
276     }
277 
278     @Test
279     public void shouldConcatThisEmptyWithNonEmpty() {
280         final Iterator<Integer> it = Iterator.of(1);
281         assertThat(Iterator.<Integer> empty().concat(it)).isSameAs(it);
282     }
283 
284     @Test
285     public void shouldConcatThisNonEmptyWithNonEmpty() {
286         assertThat(Iterator.of(1).concat(Iterator.of(2))).isEqualTo(Iterator.of(1, 2));
287     }
288 
289     // -- transform
290 
291     @Test
292     public void shouldTransform() {
293         final Iterator<?> it = Iterator.of(1, 2).transform(ii -> ii.drop(1));
294         assertThat(it).isEqualTo(Iterator.of(2));
295     }
296 
297     // -- static from(int)
298 
299     @Test
300     public void shouldGenerateIntStream() {
301         assertThat(from(-1).take(3)).isEqualTo(Iterator.of(-1, 0, 1));
302     }
303 
304     @Test
305     public void shouldGenerateOverflowingIntStream() {
306         //noinspection NumericOverflow
307         assertThat(from(Integer.MAX_VALUE).take(2))
308                 .isEqualTo(Iterator.of(Integer.MAX_VALUE, Integer.MAX_VALUE + 1));
309     }
310 
311     // -- static from(int, int)
312 
313     @Test
314     public void shouldGenerateIntStreamWithStep() {
315         assertThat(from(-1, 6).take(3)).isEqualTo(Iterator.of(-1, 5, 11));
316     }
317 
318     @Test
319     public void shouldGenerateOverflowingIntStreamWithStep() {
320         //noinspection NumericOverflow
321         assertThat(from(Integer.MAX_VALUE, 2).take(2))
322                 .isEqualTo(Iterator.of(Integer.MAX_VALUE, Integer.MAX_VALUE + 2));
323     }
324 
325     // -- static from(long)
326 
327     @Test
328     public void shouldGenerateLongStream() {
329         assertThat(from(-1L).take(3)).isEqualTo(Iterator.of(-1L, 0L, 1L));
330     }
331 
332     @Test
333     public void shouldGenerateOverflowingLongStream() {
334         //noinspection NumericOverflow
335         assertThat(from(Long.MAX_VALUE).take(2)).isEqualTo(Iterator.of(Long.MAX_VALUE, Long.MAX_VALUE + 1));
336     }
337 
338     // -- static from(long, long)
339 
340     @Test
341     public void shouldGenerateLongStreamWithStep() {
342         assertThat(from(-1L, 5L).take(3)).isEqualTo(Iterator.of(-1L, 4L, 9L));
343     }
344 
345     @Test
346     public void shouldGenerateOverflowingLongStreamWithStep() {
347         //noinspection NumericOverflow
348         assertThat(from(Long.MAX_VALUE, 2).take(2)).isEqualTo(Iterator.of(Long.MAX_VALUE, Long.MAX_VALUE + 2));
349     }
350 
351     // -- static continually(Supplier)
352 
353     @Test
354     public void shouldGenerateInfiniteStreamBasedOnSupplier() {
355         assertThat(continually(() -> 1).take(13).reduce((i, j) -> i + j)).isEqualTo(13);
356     }
357 
358     @Test
359     public void shouldGenerateInfiniteStreamBasedOnConstant() {
360         assertThat(continually(1).take(13).reduce((i, j) -> i + j)).isEqualTo(13);
361     }
362 
363     // -- static iterate(T, Function)
364 
365     @Test
366     public void shouldGenerateInfiniteStreamBasedOnSupplierWithAccessToPreviousValue() {
367         assertThat(iterate(2, (i) -> i + 2).take(3).reduce((i, j) -> i + j)).isEqualTo(12);
368     }
369 
370     @Test
371     public void shouldNotCallSupplierUntilNecessary() {
372         assertThat(iterate(2, (i) -> {
373             throw new RuntimeException();
374         }).head()).isEqualTo(2);
375     }
376 
377     // -- groupBy
378 
379     @Override
380     public void shouldNonNilGroupByIdentity() {
381         // we can't compare iterators, should map it to sequences
382         final Seq<?> actual = of('a', 'b', 'c').groupBy(Function.identity()).map(e -> Tuple.of(e._1, List.ofAll(e._2)));
383         final Seq<?> expected = HashMap.of(
384                 'a', List.ofAll(of('a')),
385                 'b', List.ofAll(of('b')),
386                 'c', List.ofAll(of('c'))).toList();
387         assertThat(actual).isEqualTo(expected);
388     }
389 
390     @Override
391     public void shouldNonNilGroupByEqual() {
392         // we can't compare iterators, should map it to sequences
393         final Seq<?> actual = of('a', 'b', 'c').groupBy(c -> 1).map(e -> Tuple.of(e._1, List.ofAll(e._2)));
394         final Seq<?> expected = HashMap.of(1, List.ofAll(of('a', 'b', 'c'))).toList();
395         assertThat(actual).isEqualTo(expected);
396     }
397 
398     @Test
399     public void shouldCreateDoubleRangeByFromInfinity() {
400         assertThat(rangeBy(Double.NEGATIVE_INFINITY, 0.0, 1.0)).startsWith(Double.NEGATIVE_INFINITY, -Double.MAX_VALUE);
401         assertThat(rangeBy(Double.POSITIVE_INFINITY, 0.0, -1.0)).startsWith(Double.POSITIVE_INFINITY, Double.MAX_VALUE);
402     }
403 
404     @Test
405     public void shouldCreateDoubleRangeClosedByFromInfinity() {
406         assertThat(rangeClosedBy(Double.NEGATIVE_INFINITY, 0.0, 1.0)).startsWith(Double.NEGATIVE_INFINITY, -Double.MAX_VALUE);
407         assertThat(rangeClosedBy(Double.POSITIVE_INFINITY, 0.0, -1.0)).startsWith(Double.POSITIVE_INFINITY, Double.MAX_VALUE);
408     }
409 
410     @Test
411     public void shouldCreateDoubleRangeByFromMaxToInfinity() {
412         assertThat(rangeBy(Double.MAX_VALUE, Double.POSITIVE_INFINITY, 3E307)).isEqualTo(of(Double.MAX_VALUE));
413         assertThat(rangeBy(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY, -3E307)).isEqualTo(of(-Double.MAX_VALUE));
414     }
415 
416     @Test
417     public void shouldCreateDoubleRangeClosedByFromMaxToInfinity() {
418         assertThat(rangeClosedBy(Double.MAX_VALUE, Double.POSITIVE_INFINITY, 3E307)).isEqualTo(of(Double.MAX_VALUE));
419         assertThat(rangeClosedBy(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY, -3E307)).isEqualTo(of(-Double.MAX_VALUE));
420     }
421 
422     @Test
423     @Override
424     public void shouldTakeUntilAllOnFalseCondition() {
425         final Iterator<Integer> actual = of(1, 2, 3).takeUntil(x -> false);
426         assertThat(actual).isEqualTo(of(1, 2, 3));
427         assertThat(actual.hasNext()).isFalse();
428     }
429 
430     @Test
431     public void shouldTakeUntilAllOnTrueCondition() {
432         final Iterator<Integer> actual = of(1, 2, 3).takeUntil(x -> true);
433         assertThat(actual).isEqualTo(empty());
434         assertThat(actual.hasNext()).isFalse();
435     }
436 
437     // -- hasNext
438 
439     @Test
440     public void multipleHasNext() {
441         multipleHasNext(() -> Iterator.of(1));
442         multipleHasNext(() -> Iterator.of(1, 2, 3));
443         multipleHasNext(() -> Iterator.ofAll(true, true, false, true));
444         multipleHasNext(() -> Iterator.ofAll(new byte[] {1, 2, 3, 4}));
445         multipleHasNext(() -> Iterator.ofAll(new char[] {1, 2, 3, 4}));
446         multipleHasNext(() -> Iterator.ofAll(new double[] {1, 2, 3, 4}));
447         multipleHasNext(() -> Iterator.ofAll(new float[] {1, 2, 3, 4}));
448         multipleHasNext(() -> Iterator.ofAll(1, 2, 3, 4));
449         multipleHasNext(() -> Iterator.ofAll(new long[] {1, 2, 3, 4}));
450         multipleHasNext(() -> Iterator.ofAll(new short[] {1, 2, 3, 4}));
451         multipleHasNext(() -> Iterator.ofAll(Iterator.of(1, 2, 3).toJavaList().iterator()));
452         multipleHasNext(() -> Iterator.ofAll(Iterator.of(1, 2, 3).toJavaList()));
453 
454         multipleHasNext(() -> Iterator.concat(List.of(Iterator.of(1, 2, 3), Iterator.of(1, 2, 3))));
455         multipleHasNext(() -> Iterator.concat(Iterator.of(1, 2, 3), Iterator.of(1, 2, 3)));
456         multipleHasNext(() -> Iterator.continually(() -> 1), 5);
457         multipleHasNext(() -> Iterator.continually(1), 5);
458         multipleHasNext(() -> Iterator.fill(3, () -> 1));
459         multipleHasNext(() -> Iterator.from(1), 5);
460         multipleHasNext(() -> Iterator.from(1, 2), 5);
461         multipleHasNext(() -> Iterator.from(1L), 5);
462         multipleHasNext(() -> Iterator.from(1L, 2L), 5);
463         multipleHasNext(() -> Iterator.iterate(1, i -> i + 1), 5);
464         multipleHasNext(() -> Iterator.tabulate(10, i -> i + 1));
465         multipleHasNext(() -> Iterator.unfold(10, x -> x == 0 ? Option.none() : Option.of(new Tuple2<>(x - 1, x))));
466         multipleHasNext(() -> Iterator.unfoldLeft(10, x -> x == 0 ? Option.none() : Option.of(new Tuple2<>(x - 1, x))));
467         multipleHasNext(() -> Iterator.unfoldRight(10, x -> x == 0 ? Option.none() : Option.of(new Tuple2<>(x, x - 1))));
468 
469         multipleHasNext(() -> Iterator.range('a', 'd'));
470         multipleHasNext(() -> Iterator.range(1, 4));
471         multipleHasNext(() -> Iterator.range(1L, 4L));
472         multipleHasNext(() -> Iterator.rangeClosed('a', 'd'));
473         multipleHasNext(() -> Iterator.rangeClosed(1, 4));
474         multipleHasNext(() -> Iterator.rangeClosed(1L, 4L));
475         multipleHasNext(() -> Iterator.rangeBy('a', 'd', 1));
476         multipleHasNext(() -> Iterator.rangeBy(1, 4, 1));
477         multipleHasNext(() -> Iterator.rangeBy(1d, 4d, 1));
478         multipleHasNext(() -> Iterator.rangeBy(1L, 4L, 1));
479         multipleHasNext(() -> Iterator.rangeClosedBy('a', 'd', 1));
480         multipleHasNext(() -> Iterator.rangeClosedBy(1, 4, 1));
481         multipleHasNext(() -> Iterator.rangeClosedBy(1d, 4d, 1));
482         multipleHasNext(() -> Iterator.rangeClosedBy(1L, 4L, 1));
483 
484         multipleHasNext(() -> Iterator.of(1, 2, 3).concat(Iterator.of(1, 2, 3)));
485         multipleHasNext(() -> Iterator.of(1, 2, 1, 2, 1, 2).distinct());
486         multipleHasNext(() -> Iterator.of(1, 2, 1, 2, 1, 2).distinctBy(e -> e % 2));
487         multipleHasNext(() -> Iterator.of(1, 2, 1, 2, 1, 2).distinctBy(Comparator.comparingInt(e -> e % 2)));
488         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).drop(1));
489         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).dropRight(1));
490         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).dropUntil(e -> e == 3));
491         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).dropWhile(e -> e == 1));
492         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).filter(e -> e > 1));
493         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).flatMap(e -> Iterator.of(e, e + 1)));
494         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).grouped(2));
495         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).intersperse(-1));
496         multipleHasNext(() -> Iterator.of(1, 2, 3).map(i -> i * 2));
497         multipleHasNext(() -> Iterator.of(1, 2, 3).partition(i -> i < 2)._1);
498         multipleHasNext(() -> Iterator.of(1, 2, 3).partition(i -> i < 2)._2);
499         multipleHasNext(() -> Iterator.of(1, 2, 3, 2).replace(2, 42));
500         multipleHasNext(() -> Iterator.of(1, 2, 3, 2).replaceAll(2, 42));
501         multipleHasNext(() -> Iterator.of(1, 2, 3).retainAll(List.of(2)));
502         multipleHasNext(() -> Iterator.of(1, 2, 3).scanLeft(1, (a, b) -> a + b));
503         multipleHasNext(() -> Iterator.of(1, 2, 3).scanRight(1, (a, b) -> a + b));
504         multipleHasNext(() -> Iterator.of(1, 2, 3).slideBy(Function.identity()));
505         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).sliding(2));
506         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).sliding(2, 1));
507         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).unzip(i -> Tuple.of(i, i + 1))._1);
508         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).unzip(i -> Tuple.of(i, i + 1))._2);
509         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).unzip3(i -> Tuple.of(i, i + 1, i + 2))._1);
510         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).unzip3(i -> Tuple.of(i, i + 1, i + 2))._2);
511         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).unzip3(i -> Tuple.of(i, i + 1, i + 2))._3);
512         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).zip(Iterator.from(1)));
513         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).zipAll(Iterator.of(1, 2), -1, -2));
514         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).zipWith(Iterator.of(1, 2), (a, b) -> a + b));
515         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).zipWithIndex());
516         multipleHasNext(() -> Iterator.of(1, 2, 3, 4).zipWithIndex((a, i) -> a + i));
517     }
518 
519     private <T> void multipleHasNext(Supplier<Iterator<T>> it) {
520         multipleHasNext(it, -1);
521     }
522 
523     private <T> void multipleHasNext(Supplier<Iterator<T>> it, int maxLen) {
524         final Iterator<T> testee1 = it.get();
525         final Iterator<T> testee2 = it.get();
526         // ask 2 times
527         assertThat(testee2.hasNext()).isTrue();
528         assertThat(testee2.hasNext()).isTrue();
529         // results should be still the same
530         if (maxLen >= 0) {
531             assertThat(testee1.take(maxLen).toList()).isEqualTo(testee2.take(maxLen).toList());
532         } else {
533             assertThat(testee1.toList()).isEqualTo(testee2.toList());
534         }
535     }
536 
537     // -- unfoldRight
538 
539     @Test
540     public void shouldUnfoldRightToEmpty() {
541         assertThat(Iterator.unfoldRight(0, x -> Option.none())).isEqualTo(empty());
542     }
543 
544     @Test
545     public void shouldUnfoldRightSimpleList() {
546         assertThat(
547                 Iterator.unfoldRight(10, x -> x == 0
548                                               ? Option.none()
549                                               : Option.of(new Tuple2<>(x, x - 1))))
550                 .isEqualTo(of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
551     }
552 
553     @Test
554     public void shouldUnfoldLeftToEmpty() {
555         assertThat(Iterator.unfoldLeft(0, x -> Option.none())).isEqualTo(empty());
556     }
557 
558     @Test
559     public void shouldUnfoldLeftSimpleList() {
560         assertThat(
561                 Iterator.unfoldLeft(10, x -> x == 0
562                                              ? Option.none()
563                                              : Option.of(new Tuple2<>(x - 1, x))))
564                 .isEqualTo(of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
565     }
566 
567     @Test
568     public void shouldUnfoldToEmpty() {
569         assertThat(Iterator.unfold(0, x -> Option.none())).isEqualTo(empty());
570     }
571 
572     @Test
573     public void shouldUnfoldSimpleList() {
574         assertThat(
575                 Iterator.unfold(10, x -> x == 0
576                                          ? Option.none()
577                                          : Option.of(new Tuple2<>(x - 1, x))))
578                 .isEqualTo(of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
579     }
580 
581     // -- class initialization (see #1773)
582 
583     @Test(timeout = 5_000)
584     public void shouldNotDeadlockOnConcurrentClassInitialization() throws InterruptedException {
585         final ExecutorService executorService = Executors.newFixedThreadPool(2);
586         executorService.execute(new ClassInitializer("io.vavr.collection.Iterator"));
587         executorService.execute(new ClassInitializer("io.vavr.collection.AbstractIterator"));
588         executorService.shutdown();
589         // try to access Vavr Iterator and it will hang
590         Iterator.empty().iterator();
591     }
592 
593     static class ClassInitializer implements Runnable {
594 
595         private String type;
596 
597         ClassInitializer(String type) {
598             this.type = type;
599         }
600 
601         @Override
602         public void run() {
603             try {
604                 Class.forName(type);
605             } catch (ClassNotFoundException e) {
606                 throw new Error(e);
607             }
608         }
609     }
610 
611     // ~~~~~~~ DISABLED TESTS ~~~~~~~
612 
613     // -- equals
614 
615     @Ignore
616     @Override
617     @Test
618     public void shouldRecognizeEqualityOfNonNils() {
619         // a equals impl would enforce evaluation which is not wanted
620     }
621 
622     @Ignore
623     @Override
624     @Test
625     public void shouldRecognizeEqualObjects() {
626         // Iterator equality undefined
627     }
628 
629     @Ignore
630     @Override
631     @Test
632     public void shouldRecognizeUnequalObjects() {
633         // Iterator equality undefined
634     }
635 
636     // -- hashCode
637 
638     @Ignore
639     @Override
640     @Test
641     public void shouldCalculateHashCodeOfNonNil() {
642         // a hashCode impl would enforce evaluation which is not wanted
643     }
644 
645     @Ignore
646     @Override
647     @Test
648     public void shouldCalculateDifferentHashCodesForDifferentTraversables() {
649         // a hashCode impl would enforce evaluation which is not wanted
650     }
651 
652     @Ignore
653     @Override
654     @Test
655     public void shouldComputeHashCodeOfEmpty() {
656         // a hashCode impl would enforce evaluation which is not wanted
657     }
658 
659     // -- isLazy
660 
661     @Override
662     @Test
663     public void shouldVerifyLazyProperty() {
664         assertThat(empty().isLazy()).isTrue();
665         assertThat(of(1).isLazy()).isTrue();
666     }
667 
668     // -- take
669 
670     @Ignore
671     @Override
672     @Test
673     public void shouldReturnSameInstanceIfTakeAll() {
674         // take consumes the Iterator
675     }
676 
677     // -- takeRight
678 
679     @Ignore
680     @Override
681     @Test
682     public void shouldReturnSameInstanceIfTakeRightAll() {
683         // takeRight consumes the Iterator
684     }
685 
686     // -- toString
687 
688     @Ignore
689     @Override
690     @Test
691     public void shouldHaveAReasonableToString() {
692         // iterators are intermediate objects and should not have an equals, hashCode or toString
693     }
694 
695     // -- spliterator
696 
697     @Test
698     public void shouldHaveOrderedSpliterator() {
699         assertThat(of(1, 2, 3).spliterator().hasCharacteristics(Spliterator.ORDERED)).isTrue();
700     }
701 
702     @Test
703     public void shouldNotHaveSortedSpliterator() {
704         assertThat(of(1, 2, 3).spliterator().hasCharacteristics(Spliterator.SORTED)).isFalse();
705     }
706 
707     @Test
708     public void shouldNotHaveSizedSpliterator() {
709         assertThat(of(1, 2, 3).spliterator().hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)).isFalse();
710     }
711 
712     @Test
713     public void shouldNotHaveDistinctSpliterator() {
714         assertThat(of(1, 2, 3).spliterator().hasCharacteristics(Spliterator.DISTINCT)).isFalse();
715     }
716 
717     @Test
718     public void shouldNotReturnSizeWhenSpliterator() {
719         assertThat(of(1, 2, 3).spliterator().getExactSizeIfKnown()).isEqualTo(-1);
720     }
721 
722     // -- isSequential()
723 
724     @Test
725     public void shouldReturnTrueWhenIsSequentialCalled() {
726         assertThat(of(1, 2, 3).isSequential()).isTrue();
727     }
728 
729 }